﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Bing.Toolkit.Data;
using Bing.Toolkit.Data.SQL;
using Bing.Toolkit.Utility;
using Microsoft.VisualStudio.TextTemplating;
using System.CodeDom.Compiler;
using System.IO;

namespace Bing.Toolkit.T4
{
    [Serializable]
    public class T4TemplatingEngineHost : ITextTemplatingEngineHost
    {
        private string _FileExtention = ".cs";
        private Encoding _FileEncoding = Encoding.UTF8;
        private string _TemplateFileValue = "test.tt";

        private CompilerErrorCollection _errorsValue;
        public CompilerErrorCollection Errors
        {
            get { return _errorsValue; }
        }

        private Dictionary<string, object> _params = new Dictionary<string, object>();
        private IList<string> _assemblyLocationList = new List<string>();
        private IList<string> _namespaceList = new List<string>();

        public T4TemplatingEngineHost()
        {
            this.AddAssemblyLocation(typeof(KeyValueObject).Assembly.Location);
            this.AddAssemblyLocation(typeof(DES).Assembly.Location);
            this.AddAssemblyLocation(typeof(T4TemplatingEngineHost).Assembly.Location);
            this.AddAssemblyLocation(typeof(AppDomain).Assembly.Location);
            this.AddAssemblyLocation(typeof(Uri).Assembly.Location);
            this.AddAssemblyLocation(typeof(DbType).Assembly.Location);
            this.AddAssemblyLocation(typeof(Queryable).Assembly.Location);

            this.AddNamespace("Bing.Toolkit.Data");
            this.AddNamespace("Bing.Toolkit.Data.SQL");
            this.AddNamespace("Bing.Toolkit.Utility");
            this.AddNamespace("System");
            this.AddNamespace("System.IO");
            this.AddNamespace("System.Xml");
            this.AddNamespace("System.Linq");
            this.AddNamespace("System.Text");
            this.AddNamespace("System.Data");
            this.AddNamespace("System.Data.Common");
            this.AddNamespace("System.Collections");
            this.AddNamespace("System.Collections.Generic");
            this.AddNamespace("System.Collections.Specialized");
        }

        public void AddAssemblyLocation(string assemblyLocation)
        {
            if (!this._assemblyLocationList.Contains(assemblyLocation))
            {
                this._assemblyLocationList.Add(assemblyLocation);
            }
        }

        public void AddNamespace(string namespaceName)
        {
            if (!this._namespaceList.Contains(namespaceName))
            {
                this._namespaceList.Add(namespaceName);
            }
        }

        public void SetParam(string key, object val)
        {
            if (!this._params.ContainsKey(key))
            {
                this._params.Add(key, val);
            }
        }
        public T GetParma<T>(string key)
        {
            if (this._params.ContainsKey(key))
            {
                return default(T);
            }
            else
            {
                var retStr = Convert.ChangeType(this._params[key], typeof(T));
                return (T)retStr;
            }
        }

        public string FirstLetter(string strField)
        { 
            var strTemp = strField.Trim();

            if(strTemp.Length > 0)
            {
                return strTemp[0].ToString().ToUpper() + strTemp.Substring(1);
            }
            return String.Empty;
        }

        public string FirstLetter(string strField, string strSeparator)
        {
            var arrTemp = strField.Split(new string[] { strSeparator }, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder sb = new StringBuilder();
            foreach (var entry in arrTemp)
            {
                sb.Append(FirstLetter(entry));
            }
            return sb.ToString();
        }

        public string GetCSharpType(string dbType)
        {
            switch (dbType.ToLower())
            {
                case "datetime":
                    return "DateTime";
                case "varchar":
                case "nvarchar":
                case "char":
                case "nchar":
                case "text":
                case "ntext":
                case "date":
                case "time":
                case "xml":
                    return "string";
                case "uniqueidentifier":
                    return "Guid";
                case "bigint":
                    return "long";
                case "int":
                    return "int";
                case "smallint":
                    return "short";
                case "tinyint":
                    return "Byte";
                case "decimal":
                case "money":
                case "numeric":
                    return "decimal";
                case "image":
                    return "byte[]";
                case "float":
                    return "double";
                case "bit":
                    return "bool";
                default:
                    return "Object";
            }
        }

        public object GetHostOption(string optionName)
        {
            object returnObject;
            switch (optionName)
            {
                case "CacheAssemblies":
                    returnObject = true;
                    break;
                default:
                    returnObject = null;
                    break;
            }
            return returnObject;
        }

        public bool LoadIncludeText(string requestFileName, out string content, out string location)
        {
            content = System.String.Empty;
            location = System.String.Empty;

            if (File.Exists(requestFileName))
            {
                content = File.ReadAllText(requestFileName);
                return true;
            }
            else
            {
                return false;
            }
        }

        public void LogErrors(CompilerErrorCollection errors)
        {
            _errorsValue = errors;
        }

        public AppDomain ProvideTemplatingAppDomain(string content)
        {
            return AppDomain.CreateDomain("Generation App Domain");
        }

        public string ResolveAssemblyReference(string assemblyReference)
        {
            if (File.Exists(assemblyReference))
            {
                return assemblyReference;
            }
            string path = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
            if (File.Exists(path))
            {
                return path;
            }
            return string.Empty;
        }

        public Type ResolveDirectiveProcessor(string processorName)
        {
            if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //return typeof();
            }

            throw new Exception("Directive Processor not found");
        }

        public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
        {
            if (directiveId == null)
            {
                throw new ArgumentNullException("the directiveId cannot be null");
            }
            if (processorName == null)
            {
                throw new ArgumentNullException("the processorName cannot be null");
            }
            if (parameterName == null)
            {
                throw new ArgumentNullException("the parameterName cannot be null");
            }
            return string.Empty;

        }

        public string ResolvePath(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException("the path cannot be null");
            }
            if (!File.Exists(path))
            {
                string str = Path.Combine(Path.GetDirectoryName(this.TemplateFile), path);
                if (File.Exists(str))
                {
                    return str;
                }
            }
            return path;

        }

        public void SetFileExtension(string extension)
        {
            this._FileExtention = extension;
        }

        public void SetOutputEncoding(Encoding encoding, bool fromOutputDirective)
        {
            _FileEncoding = encoding;
        }

        public IList<string> StandardAssemblyReferences
        {
            get { return _assemblyLocationList; }
        }

        public IList<string> StandardImports
        {
            get { return _namespaceList; }
        }

        public string TemplateFile
        {
            get { return _TemplateFileValue; }
            set { _TemplateFileValue = value; }
        }
    }
}
